home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / bmutil.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  36KB  |  1,468 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  *
  13.  *  Userlogging, 'RM' and 'KM' implementation,
  14.  *  more-prompts for all types
  15.  *  920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
  16.  */
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #include <time.h>
  21. #include "global.h"
  22. #include "config.h"
  23. #include "ftpserv.h"
  24. #include "smtp.h"
  25. #include "proc.h"
  26. #include "usock.h"
  27. #include "socket.h"
  28. #include "telnet.h"
  29. #include "timer.h"
  30. #include "session.h"
  31. #include "files.h"
  32. #include "mailbox.h"
  33. #include "cmdparse.h"
  34. #include "bm.h"
  35. #include "mailutil.h"
  36. #include "dirutil.h"
  37.  
  38. #ifndef UNIX
  39. #define        SETVBUF
  40. #endif
  41. #if    defined(UNIX) || defined(MICROSOFT)
  42. #include    <sys/types.h>
  43. #endif
  44. /*
  45. #if    defined(UNIX) || defined(MICROSOFT) || defined(__TURBOC__)
  46. #include    <sys/stat.h>
  47. #endif
  48. #ifdef AZTEC
  49. #include <stat.h>
  50. #endif
  51. */
  52. #include <fcntl.h>
  53. #include "bm.h"
  54. #include "mailbox.h"
  55.  
  56. #ifdef SETVBUF
  57. #define        MYBUF    1024
  58. #endif
  59.  
  60. /*extern long ftell();*/
  61. char Badmsg[] = "Invalid Message number %d\n";
  62. char Nomail[] = "No messages\n";
  63. static char Noaccess[] = "Unable to access %s\n";
  64. static int readnotes __ARGS((struct mbx *m,FILE *ifile,int update));
  65. static long isnewmail __ARGS((struct mbx *m));
  66. static int initnotes __ARGS((struct mbx *m));
  67. static int lockit __ARGS((struct mbx *m));
  68. static void mfclose __ARGS((struct mbx *m));
  69.  
  70. #ifdef MAILBOX
  71.  
  72. static int
  73. initnotes(m)
  74. struct mbx *m;
  75. {
  76.     FILE    *tmpfile __ARGS((void));
  77.     FILE    *ifile;
  78.     register struct    let *cmsg;
  79.     char buf[256];
  80.     int     i, ret;
  81.  
  82.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  83.     if ((ifile = fopen(buf,READ_TEXT)) == NULLFILE)
  84.         return 0;
  85.     fseek(ifile,0L,2);     /* go to end of file */
  86.     m->mboxsize = ftell(ifile);
  87.     rewind(ifile);
  88.     if(!stricmp(m->area,m->name)) /* our private mail area */
  89.         m->mysize = m->mboxsize;
  90.     if ((m->mfile = tmpfile()) == NULLFILE) {
  91.         (void) fclose(ifile);
  92.         return -1;
  93.     }
  94. #ifdef    SETVBUF
  95.     if (m->stdinbuf == NULLCHAR)
  96.         m->stdinbuf = mallocw(MYBUF);
  97.     setvbuf(ifile, m->stdinbuf, _IOFBF, MYBUF);
  98.     if (m->stdoutbuf == NULLCHAR)
  99.         m->stdoutbuf = mallocw(MYBUF);
  100.     setvbuf(m->mfile, m->stdoutbuf, _IOFBF, MYBUF);
  101. #endif
  102.     m->nmsgs = 0;
  103.     m->current = 0;
  104.     m->change = 0;
  105.     m->newmsgs = 0;
  106.     m->anyread = 0;
  107.     /* Allocate space for reading messages */
  108.     free((char *)m->mbox);
  109.     m->mbox = (struct let *)callocw(Maxlet+1,sizeof(struct let));
  110.     ret = readnotes(m,ifile,0);
  111.     (void) fclose(ifile);
  112. #ifdef SETVBUF
  113.     free(m->stdinbuf);
  114.     m->stdinbuf = NULLCHAR;
  115. #endif
  116.     if (ret != 0)
  117.         return -1;
  118.  
  119. #ifdef USERLOG
  120.     /*Check for unread(ie. new) messages
  121.      */
  122.     m->current = m->newmsgs = 0; /*reset it*/
  123. #endif
  124.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++)
  125.         if ((cmsg->status & BM_READ) == 0) {
  126.             m->newmsgs++;
  127.             if (m->current == 0)
  128.                 m->current = i; /* first new message */
  129.         }
  130.  
  131.     /* start at one if no new messages */
  132.     if (m->current == 0)
  133.         m->current++;
  134.  
  135.     return 0;
  136. }
  137.  
  138. /* readnotes assumes that ifile is pointing to the first
  139.  * message that needs to be read.  For initial reads of a
  140.  * notesfile, this will be the beginning of the file.  For
  141.  * rereads when new mail arrives, it will be the first new
  142.  * message.
  143.  */
  144. static int
  145. readnotes(m,ifile,update)
  146. struct mbx *m;
  147. FILE *ifile ;
  148. int update;    /* true if this is not the initial read of the notesfile */
  149. {
  150.     char     tstring[LINELEN];
  151.     long    cpos;
  152.     register struct    let *cmsg;
  153.     register char *line;
  154. #ifdef USERLOG
  155.     char *cp;
  156.     long msgid;
  157. #endif
  158.  
  159.     cmsg = (struct let *)NULL;
  160.     line = tstring;
  161.     while(fgets(line,LINELEN,ifile) != NULLCHAR) {
  162.         /* scan for begining of a message */
  163.         if(strncmp(line,"From ",5) == 0) {
  164.             pwait(NULL);
  165.             cpos = ftell(m->mfile);
  166.             fputs(line,m->mfile);
  167. #ifdef notdef
  168.             /* if full, we allow the first Maxlet messages to be read - WG7J */
  169.             if (m->nmsgs == Maxlet) {
  170.                 tprintf("Mail box full: > %d messages\n",Maxlet);
  171.                 mfclose(m);
  172.                 return -1;
  173.             }
  174. #endif
  175.             m->nmsgs++;
  176.             cmsg = &m->mbox[m->nmsgs];
  177.             cmsg->start = cpos;
  178.             if(!update)
  179.                 cmsg->status = 0;
  180.             cmsg->size = strlen(line);
  181. #ifdef USERLOG
  182.             if(fgets(line,LINELEN,ifile) != NULLCHAR){ /* "Received line" */
  183.                 fputs(line,m->mfile);
  184.                 cmsg->size += strlen(line);
  185.                 if(fgets(line,LINELEN,ifile) != NULLCHAR) { /* "id line" */
  186.                     fputs(line,m->mfile);
  187.                     cmsg->size += strlen(line);
  188.                     if((cp=strstr(line,"AA")) != NULLCHAR) {
  189.                         /*what follows is the message-number*/
  190.                         msgid = atol(cp+2);
  191.                         if(msgid > m->lastread)
  192.                             m->newmsgs++;
  193.                         else
  194.                             cmsg->status |= BM_READ;
  195.                     }
  196.                 }
  197.             }
  198. #endif
  199.  
  200.             while (fgets(line,LINELEN,ifile) != NULLCHAR) {
  201.                 if (*line == '\n') { /* done header part */
  202.                     cmsg->size++;
  203.                     putc(*line, m->mfile);
  204.                     break;
  205.                 }
  206.                 if (htype(line) == STATUS) {
  207.                     if (line[8] == 'R') 
  208.                         cmsg->status |= BM_READ;
  209.                     continue;
  210.                 }
  211.                 if(htype(line) == XBBSHOLD) {
  212.                     cmsg->status |= BM_HOLD;
  213.                     continue;
  214.                 }
  215.                 cmsg->size += strlen(line);
  216.                 if (fputs(line,m->mfile) == EOF) {
  217.                     tprintf("tmp file: %s",sys_errlist[errno]);
  218.                     mfclose(m);
  219.                     return -1;
  220.                 }
  221.  
  222.             }
  223.         /* stop if full - WG7J */
  224.         if(m->nmsgs == Maxlet)
  225.             return 0;
  226.         } else if (cmsg) {
  227.             cmsg->size += strlen(line);
  228.             fputs(line,m->mfile);
  229.         }
  230.     }
  231.     return 0;
  232. }
  233.  
  234. /* list headers of a notesfile a message */
  235. /* Rearranged display - WG7J */
  236. int
  237. dolistnotes(argc,argv,p)
  238. int argc;
  239. char *argv[];
  240. void *p;
  241. {
  242.     struct mbx *m;
  243.     register struct    let *cmsg;
  244.     register char    *cp, *s;
  245.     char smtp_date[SLINELEN], smtp_from[SLINELEN];
  246.     char smtp_subject[SLINELEN], tstring[LINELEN], type;
  247.     char smtp_to[SLINELEN];
  248.     int start, stop;
  249.     long    size;
  250.     char    *area;
  251.     int c,usemore=0,lin;
  252. #ifdef USERLOG
  253.     long msgid;
  254. #endif
  255.  
  256.     m = (struct mbx *) p;
  257.  
  258.     /*If this user doesn't have read-permissions,
  259.      *we're not going to let him list anything - WG7J
  260.      */
  261.     if(m->privs & NO_READCMD) {
  262.         tputs(Noperm);
  263.         return 0;
  264.     }
  265.  
  266.     if (m->mfile == NULLFILE) {
  267.         tputs(Nomail);
  268.         return 0;
  269.     }
  270.     if((m->stype == '>' || m->stype == '<') && argc == 1) {
  271.             tputs("Search criterium needed!\n");
  272.             return 0;
  273.         }
  274.  
  275.     if((lin=m->morerows) != 0)
  276.         usemore = 1;    /* Display More prompt */
  277.  
  278.     area = strdup(m->area);
  279.     while((cp = strchr(area,'/')) != NULLCHAR)
  280.         *cp = '.';
  281.     tprintf("Mail area: %s  %d message%s -  %d new\n\n"
  282.             "St.  #        TO         FROM  DATE    SIZE SUBJECT\n",
  283.             area,m->nmsgs,m->nmsgs == 1 ? " " : "s ", m->newmsgs);
  284.     free(area);
  285.  
  286.     stop = m->nmsgs;
  287.     if(m->stype == 'L') {        /* LL (List Latest) command */
  288.         if(argc > 1) {
  289.           start = stop - atoi(argv[1]) + 1;
  290.           if(start <= 0)
  291.             start = 1;
  292.         } else
  293.           start = stop;
  294.     } else {
  295.         if((m->stype == 'A') || (m->stype == '>') || (m->stype == '<')) {
  296.             start = 1;
  297.             stop = m->nmsgs;
  298.         } else {
  299.             if(argc > 1)
  300.                 start = atoi(argv[1]);
  301.             else
  302. #ifdef USERLOG
  303.                 start = m->nmsgs - m->newmsgs + 1;
  304. #else
  305.                 start = 1;
  306. #endif
  307.             if(argc > 2)
  308.                 stop = atoi(argv[2]);
  309.         }
  310.     }
  311.     if(stop > m->nmsgs)
  312.         stop = m->nmsgs;
  313.     if(start < 1 || start > stop) {
  314.         if((m->stype == ' ') || (m->stype == 'M'))
  315.             tputs("No new mail.\n");
  316.         else
  317.             tputs("Invalid range.\n");
  318.         return 0;
  319.     }
  320.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  321.         *smtp_date = '\0';
  322.         *smtp_from = '\0';
  323.         *smtp_subject = '\0';
  324.         *smtp_to = '\0';
  325.         type = ' ';
  326.         fseek(m->mfile,cmsg->start,0);
  327.         size = cmsg->size;
  328.         /* Be a little less selfish - WG7J */
  329.         pwait(NULL);
  330.  
  331. #ifdef USERLOG
  332. /* We need to get the id from the last message listed !
  333.  * m->mbox[i].start (ie cmsg->start) points to the 'From ' line
  334.  * next are the 'Received....' and 'ID...' lines
  335.  * These are thes line added by our smtp server.
  336.  * following the 'AA' is the number that we want ! - WG7J
  337.  */
  338.         if(start == stop) {
  339.             /*The 'From ' line*/
  340.             fgets(tstring,sizeof(tstring),m->mfile);
  341.             size -= strlen(tstring);
  342.             /*The 'Received' line*/
  343.             fgets(tstring,sizeof(tstring),m->mfile);
  344.             size -= strlen(tstring);
  345.             /*The 'ID' line*/
  346.             fgets(tstring,sizeof(tstring),m->mfile);
  347.             size -= strlen(tstring);
  348.             /* find id number */
  349.             if((cp=strstr(tstring,"AA")) != NULLCHAR) {
  350.                 /*what follows is the message-number*/
  351.                 msgid = atol(cp+2);
  352.                 if(msgid > m->lastread)
  353.                     m->newlastread = msgid;
  354.             }
  355.         }
  356. #endif
  357.  
  358.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  359.                != NULLCHAR) {
  360.             pwait(NULL);
  361.             if (*tstring == '\n')   /* end of header */
  362.                 break;
  363.             size -= strlen(tstring);
  364.             rip(tstring);
  365.             /* handle continuation later */
  366.             if (*tstring == ' '|| *tstring == '\t')
  367.                 continue;
  368.             switch(htype(tstring)) {
  369.             case FROM:
  370.                 cp = getaddress(tstring,0);
  371.                 sprintf(smtp_from,"%s",
  372.                     cp != NULLCHAR ? cp : "");
  373.                 if((cp=strchr(smtp_from,'@')) != NULLCHAR)
  374.                     *cp = '\0';         /* get rid of @-host or @-bbs field */
  375.                 break;
  376.             case SUBJECT:
  377.                 sprintf(smtp_subject,"%s",&tstring[9]);
  378.                 break;
  379.             case DATE:
  380.                 if ((cp = strchr(tstring,',')) == NULLCHAR)
  381.                     cp = &tstring[6];
  382.                 else
  383.                     cp++;
  384.                 /* skip spaces */
  385.                 while (*cp == ' ') cp++;
  386.                 if(strlen(cp) < 17)
  387.                     break;     /* not a valid length */
  388.                 s = smtp_date;
  389.                 /* copy day */
  390.                 if (atoi(cp) < 10 && *cp != '0') {
  391.                     *s++ = ' ';
  392.                 } else
  393.                     *s++ = *cp++;
  394.                 *s++ = *cp++;
  395.  
  396.                 *s++ = ' ';
  397.                 *s = '\0';
  398.                 while (*cp == ' ')
  399.                     cp++;
  400.                 strncat(s,cp,3);    /* copy month */
  401. #ifdef use_time
  402.                 cp += 3;
  403.                 while (*cp == ' ')
  404.                     cp++;
  405.                 /* skip year */
  406.                 while (isdigit(*cp))
  407.                     cp++;
  408.                 /* copy time */
  409.                 strncat(s,cp,6); /* space hour : min */
  410. #endif
  411.                 break;
  412.             case BBSTYPE:
  413.                 type = tstring[16];
  414.                 break;
  415.             case TO:
  416.                 sprintf(smtp_to,"%s",&tstring[4]);
  417.                 break;
  418.             case NOHEADER:
  419.                 break;
  420.             }
  421.         }
  422.         if(m->stype == ' ' || m->stype == 'L' || m->stype == 'M' ||
  423.            m->stype == 'A' || (type == m->stype && m->stype != ' ') ||
  424.            ((m->stype == '<') && (strstr(strlwr(smtp_from),argv[1]) != NULLCHAR)) ||
  425.            ((m->stype == '>') && (strstr(strlwr(smtp_to),argv[1]) != NULLCHAR))
  426.            ) {
  427.                 lin--;
  428.                 tprintf("%c%c%c%3d %13.13s %8.8s %-7.7s %5ld %.35s\n",
  429.                  (start == m->current ? '>' : ' '),
  430.                  (cmsg->status & BM_DELETE ? 'D' : ' '),
  431.                  (cmsg->status & BM_HOLD ? 'H':(cmsg->status & BM_READ ? 'Y' : 'N')),
  432.                  start, smtp_to, smtp_from,smtp_date,
  433.                  cmsg->size, smtp_subject);
  434.            }
  435.         /* More prompting added - WG7J */
  436.         if(usemore && lin == 0){
  437.             if(m->type == TELNET_LINK || m->type == TIP_LINK)
  438.                 c = tkeywait("--More--",0,m->linemode);
  439.             else  /* For AX.25 and NET/ROM connects - WG7J */
  440.                 c = mykeywait("More(N=no)? ",m);
  441.             if(c == -1 || c == 'q' || c == 'Q')
  442.                 break;
  443.             if(c == '\n' || c == '\r')
  444.                 lin = 1;
  445.             else
  446.                 lin = m->morerows;
  447.  
  448.         }
  449.     }
  450.     return 0;
  451. }
  452.  
  453. /*  save msg on stream - if noheader set don't output the header */
  454. int
  455. msgtofile(m,msg,tfile,noheader)
  456. struct mbx *m;
  457. int msg;
  458. FILE *tfile;   /* already open for write */
  459. int noheader;
  460. {
  461.     char    tstring[LINELEN];
  462.     long     size;
  463.  
  464.     if (m->mfile == NULLFILE) {
  465.         tprintf(Nomail);
  466.         return -1;
  467.     }
  468.     fseek(m->mfile,m->mbox[msg].start,0);
  469.     size = m->mbox[msg].size;
  470.  
  471.     if (noheader) {
  472.         /* skip header */
  473.         while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  474.                != NULLCHAR) {
  475.             size -= strlen(tstring);
  476.             if (*tstring == '\n')
  477.                 break;
  478.         }
  479.     }
  480.     while (size > 0 && fgets(tstring,sizeof(tstring),m->mfile)
  481.            != NULLCHAR) {
  482.         size -= strlen(tstring);
  483.         fputs(tstring,tfile);
  484.         if (ferror(tfile)) {
  485.             tprintf("Error writing mail file\n");
  486.             return -1;
  487.         }
  488.     }
  489.     return 0;
  490. }
  491.  
  492. /* dodelmsg - delete message in current notesfile */
  493. /* Modified to allow the 'KM' command. 920307 -  WG7J */
  494. int
  495. dodelmsg(argc,argv,p)
  496. int argc;
  497. char *argv[];
  498. void *p;
  499. {
  500.     struct mbx *m;
  501.     int msg,i;
  502.     char *myargv[NARG];
  503.     int myargc;
  504.     int maxmsg;
  505.     struct let *cmsg;
  506.     char *tmpbuf;
  507.  
  508.     m = (struct mbx *) p;
  509.  
  510.     /* If this user doesn't have read-permissions,
  511.      * we're not going to let him kill anything;
  512.      * allow anyone to kill messages in areas
  513.      * who's names start with 'nts' - WG7J
  514.      */
  515.     /* Check if we have permission to delete others mail */
  516.     if( (m->privs & NO_SENDCMD) ||
  517.         (m->privs & NO_READCMD) ||
  518.         ( !(m->privs & FTP_WRITE) &&
  519.             stricmp(m->area,m->name) &&
  520.             strnicmp(m->area,"nts",3)) ){
  521.         tputs(Noperm);
  522.         return 0;
  523.     }
  524.     if (m->mfile == NULLFILE) {
  525.         tputs(Nomail);
  526.         return 0;
  527.     }
  528.     /*If this is the KM command, setup myargv[]
  529.      *to contain up to NARG message numbers - WG7J
  530.      */
  531.     if(m->stype == 'M') {
  532.         myargc = 1;
  533.         /* scan all messsages to find read ones */
  534.         maxmsg = min(m->nmsgs,NARG-1);
  535.         for(i=1;i<=maxmsg;i++){
  536.             cmsg = &m->mbox[i];
  537.             if(cmsg->status & BM_READ) { /*found a read msg!*/
  538.                 tmpbuf = mallocw(17); /*allocate space for the new argument*/
  539.                 myargv[myargc++] = itoa(i,tmpbuf,10);
  540.             }
  541.         }
  542.         if(myargc == 1) {
  543.             tputs("Nothing to kill\n");
  544.             return 0;
  545.         }
  546.         argc = myargc;
  547.     } else {
  548.         if(argc == 1) {
  549.             tputs("Usage: Kill #\n");
  550.             return 0;
  551.         }
  552.         /*simply point to the old arguments*/
  553.         for(i=1;i<argc;i++)
  554.             myargv[i] = argv[i];
  555.     }
  556.  
  557.     for(i = 1; i < argc; ++i) {
  558.     tmpbuf = strchr(myargv[i],'-');    /* N5KNX: allow from-to msg specification */
  559.     msg = atoi(myargv[i]);
  560.     if (tmpbuf == NULLCHAR) maxmsg = msg;
  561.     else maxmsg = atoi(++tmpbuf);
  562.     if (maxmsg < msg) {
  563.         tprintf(Badmsg,myargv[i]);
  564.         continue;
  565.     }
  566.     for (; msg <= maxmsg; msg++) {
  567.         if(msg < 0 || msg > m->nmsgs) {
  568.             tprintf(Badmsg,msg);
  569.             continue;
  570.         }
  571.             if(m->stype == 'U')
  572.                 m->mbox[msg].status &= ~BM_DELETE;
  573.             else
  574.                 m->mbox[msg].status |= BM_DELETE;
  575.             tprintf("Msg %d %sKilled.\n", msg,(m->stype=='U') ? "Un-" : "");
  576.         m->change = 1;
  577.     }
  578.     }
  579.     /* If this was 'KM'
  580.      * free the memory allocated for myargv[] - WG7J
  581.      */
  582.     if(m->stype == 'M') {
  583.         for(i=1;i<argc;i++)
  584.             free(myargv[i]);
  585.     }
  586.     return 0;
  587. }
  588. /* close the temp file while coping mail back to the mailbox */
  589. int
  590. closenotes(m)
  591. struct mbx *m;
  592. {
  593.     register struct    let *cmsg;
  594.     register char *line;
  595.     char tstring[LINELEN], buf[256];
  596.     long size;
  597.     int i, nostatus = 0, nodelete;
  598.     FILE    *nfile;
  599.  
  600.     if (m->mfile == NULLFILE)
  601.         return 0;
  602.  
  603.     if(!m->change) {        /* no changes were made */
  604.         mfclose(m);
  605.         m->mboxsize = 0;
  606.         return 0;
  607.     }
  608.     /* If this area is a public message area, then we will not add a
  609.      * Status line to indicate that the message has been read.
  610.      */
  611.     nostatus = isarea(m->area);
  612.  
  613.     /* Don't delete messages from public message areas unless you are
  614.      * a BBS.
  615.      */
  616.     /* Allow any user to delete from area names starting with 'nts' - WG7J */
  617.     if(nostatus) {
  618.         if(!strnicmp(m->area,"nts",3))
  619.             nodelete = 0;
  620.         else
  621.             nodelete = !(m->privs & SYSOP_CMD);
  622.     } else
  623.         nodelete = 0;
  624.  
  625.     /* See if any messages have been forwarded, otherwise just close
  626.      * the file and return since there is nothing to write back.
  627.      */
  628.     if(nostatus && nodelete) {
  629.         for(i=1; i <= m->nmsgs; ++i)
  630.             if(m->mbox[i].status & BM_FORWARDED)
  631.                 break;
  632.         if(i > m->nmsgs) {
  633.             mfclose(m);
  634.             m->mboxsize = 0;
  635.             return 0;
  636.         }
  637.     }
  638.     line = tstring;
  639.     scanmail(m);
  640.     if(lockit(m))
  641.         return -1;
  642.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  643.     if ((nfile = fopen(buf,WRITE_TEXT)) == NULLFILE) {
  644.         tprintf(Noaccess,buf);
  645.         mfclose(m);
  646.         m->mboxsize = 0;
  647.         rmlock(Mailspool,m->area);
  648.         return -1;
  649.     }
  650.     /* copy tmp file back to notes file */
  651.     for (cmsg = &m->mbox[1],i = 1; i <= m->nmsgs; i++, cmsg++) {
  652.         fseek(m->mfile,cmsg->start,0);
  653.         size = cmsg->size;
  654.         /* It is not possible to delete messages if nodelete is set */
  655.         if ((cmsg->status & BM_DELETE) && !nodelete)
  656.             continue;
  657.         /* copy the header */
  658.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  659.             size -= strlen(line);
  660.             if (*line == '\n') {
  661.                 if (cmsg->status & BM_FORWARDED)
  662.                     fprintf(nfile,"%s%s\n",Hdrs[XFORWARD],
  663.                         m->name);
  664.                 if ((cmsg->status & BM_READ) != 0 && !nostatus)
  665.                     fprintf(nfile,"%sR\n",Hdrs[STATUS]);
  666.                 fprintf(nfile,"\n");
  667.                 break;
  668.             }
  669.             fputs(line,nfile);
  670.             /* pwait(NULL);  can cause problems if exiting NOS */
  671.         }
  672.         while (size > 0 && fgets(line,LINELEN,m->mfile) != NULLCHAR) {
  673.             fputs(line,nfile);
  674.             size -= strlen(line);
  675.             /* pwait(NULL);   dont want no damaged files */
  676.             if (ferror(nfile)) {
  677.                 tprintf("Error writing mail file\n");
  678.                 (void) fclose(nfile);
  679.                 mfclose(m);
  680.                 m->mboxsize = 0;
  681.                 rmlock(Mailspool,m->area);
  682.                 return -1;
  683.             }
  684.         }
  685.     }
  686.     m->nmsgs = 0;
  687.     if (!stricmp(m->name,m->area))
  688.         m->mysize = ftell(nfile); /* Update the size of our mailbox */
  689.     /* remove a zero length file */
  690.     if (ftell(nfile) == 0L)
  691.         (void) unlink(buf);
  692.     (void) fclose(nfile);
  693.     mfclose(m);
  694.     m->mboxsize = 0;
  695.     rmlock(Mailspool,m->area);
  696.     pwait(NULL);
  697.     return 0;
  698. }
  699.  
  700. /* Returns 1 if name is a public message Area, 0 otherwise */
  701. int
  702. isarea(name)
  703. char *name;
  704. {
  705.     char buf[LINELEN], *cp;
  706.     FILE *fp;
  707.     if((fp = fopen(Arealist,READ_TEXT)) == NULLFILE)
  708.         return 0;
  709.     while(fgets(buf,sizeof(buf),fp) != NULLCHAR) {
  710.         /* The first word on each line is all that matters */
  711.         if((cp = strchr(buf,' ')) != NULLCHAR)
  712.             *cp = '\0';
  713.         /*There could still be a tab before the space ! -WG7J */
  714.         if((cp = strchr(buf,'\t')) != NULLCHAR)
  715.             *cp = '\0';
  716.         /*This could be a line with just the area name,
  717.          *ie terminated with 'CR/LF' - WG7J
  718.          */
  719.         if((cp = strchr(buf,'\n')) != NULLCHAR)
  720.             *cp = '\0';
  721.         if(stricmp(name,buf) == 0) {    /* found it */
  722.             fclose(fp);
  723.             return 1;
  724.         }
  725.     }
  726.     fclose(fp);
  727.     return 0;
  728. }
  729.  
  730. static int
  731. lockit(m)
  732. struct mbx *m;
  733. {
  734.     int c, cnt = 0;
  735.  
  736.     while(mlock(Mailspool,m->area)) {
  737.         pause(1000L);   /* Wait one second */
  738.         if(++cnt == 10) {
  739.             cnt = 0;
  740.             switch (m->state) {
  741.             case MBX_REVFWD:
  742.             case MBX_FORWARD:
  743.             case MBX_TRYING:
  744.                 c='A';
  745.                 break;
  746.             default:
  747.                 c = tkeywait("Mail file is busy, Abort or Retry ? ",1,m->linemode);
  748.                 break;
  749.             }
  750.             if (c == 'A' || c == 'a' || c == EOF) {
  751.                 mfclose(m);
  752.                 return 1;
  753.             }
  754.         }
  755.     }
  756.     return 0;
  757. }
  758.  
  759. /* read the next message or the current one if new */
  760. int
  761. doreadnext(argc,argv,p)
  762. int argc;
  763. char *argv[];
  764. void *p;
  765. {
  766.     struct mbx *m;
  767.     char buf[10], *newargv[2];
  768.     m = (struct mbx *) p;
  769.     if (m->mfile == NULLFILE)
  770.         return 0;
  771.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  772.         if (m->current == 1 && m->anyread == 0)
  773.             ;
  774.         else if (m->current < m->nmsgs) {
  775.             m->current++;
  776.         } else {
  777.             tprintf("Last message\n");
  778.             return 0;
  779.         }
  780.     }
  781.     sprintf(buf,"%d",m->current);
  782.     newargv[0] = "read";
  783.     newargv[1] = buf;
  784.     m->anyread = 1;
  785.     return doreadmsg(2,newargv,p);
  786. }
  787.  
  788. extern int MbRead;
  789.  
  790. /* display message on the crt given msg number */
  791. /* Modified to allow the 'RM' command, 920307 - WG7J */
  792. int
  793. doreadmsg(argc,argv,p)
  794. int argc;
  795. char *argv[];
  796. void *p;
  797. {
  798.     struct mbx *m;
  799.     register int c, col, lin;
  800.     char    buf[MAXCOL+2], *cp, *cp2;
  801.     int msg, cnt, i, usemore=0, verbose, mbxheader, pathcol;
  802.     int    header, lastheader;
  803.     long     size;
  804.     char *myargv[NARG];
  805.     int myargc;
  806.     int maxmsg;
  807.     struct let *cmsg;
  808.     char *tmpbuf;
  809. #ifdef USERLOG
  810.     long msgid;
  811. #endif
  812.  
  813.     m = (struct mbx *) p;
  814.  
  815.     /*Check for read-permissions - WG7J */
  816.     if(m->privs & NO_READCMD) {
  817.         tputs(Noperm);
  818.         return 0;
  819.     }
  820.     if (m->mfile == NULLFILE) {
  821.         tprintf(Nomail);
  822.         return 0;
  823.     }
  824.     if((lin=m->morerows) != 0)
  825.         usemore = 1;    /* Display More prompt */
  826.  
  827.     /*If this is the RM or VM command, setup myargv[]
  828.      *to contain up to NARG message numbers - WG7J
  829.      */
  830.     if(m->stype == 'M') {
  831.         myargc = 1;
  832.         /* scan all messsages to find unread ones */
  833.         maxmsg = min(m->nmsgs,NARG-1);
  834.         for(i=1;i<=maxmsg;i++){
  835.             cmsg = &m->mbox[i];
  836.             if(!(cmsg->status & BM_READ)) { /*found an unread msg!*/
  837.                 tmpbuf = mallocw(17); /*allocate space for the new argument*/
  838.                 myargv[myargc++] = itoa(i,tmpbuf,10);
  839.             }
  840.         }
  841.         argc = myargc;
  842.     } else {
  843.         /*simply point to the old arguments*/
  844.         for(i=1;i<argc;i++)
  845.             myargv[i] = argv[i];
  846.     }
  847.     if(argc == 1) {
  848.         tputs("Usage: Read/Verbose #\n");
  849.         return 0;
  850.     }
  851.     m->state = MBX_READ;
  852.     for(i = 1; i < argc; ++i) {
  853.       tmpbuf = strchr(myargv[i],'-');    /* N5KNX: allow from-to msg specification */
  854.       msg = atoi(myargv[i]);
  855.       if (tmpbuf == NULLCHAR) maxmsg = msg;
  856.       else maxmsg = atoi(++tmpbuf);
  857.       if (maxmsg < msg) {
  858.     tprintf(Badmsg,myargv[i]);
  859.     continue;
  860.       }
  861.       for (; msg <= maxmsg; msg++) {
  862.         /* if the message is on hold, only show to sysops - WG7J */
  863.         if((m->mbox[msg].status & BM_HOLD) && !(m->privs & SYSOP_CMD)) {
  864.             tprintf("Msg %d:",msg);
  865.             tputs(Noperm);
  866.             continue;
  867.         }
  868.         if( msg < 1 || msg > m->nmsgs) {
  869.             tprintf(Badmsg,msg);
  870.             goto iamdone;
  871.         }
  872. #ifdef MAILCMDS
  873.         MbRead++;
  874. #endif
  875.         fseek(m->mfile,m->mbox[msg].start,0);
  876. #ifdef USERLOG
  877.         /* Check the ID number of this message and
  878.          * adjust new lastread count, if needed - WG7J
  879.          */
  880.         fgets(buf,MAXCOL+2,m->mfile);    /* the 'From ' line */
  881.         fgets(buf,MAXCOL+2,m->mfile);    /* the 'Received: ' line */
  882.         fgets(buf,MAXCOL+2,m->mfile);    /* the ' ID' line */
  883.         /* find id number */
  884.         if((cp=strstr(buf,"AA")) != NULLCHAR) {
  885.         /*what follows is the message-number*/
  886.             msgid = atol(cp+2);
  887.             if(msgid > m->lastread)
  888.                 m->newlastread = msgid;
  889.             }
  890.         fseek(m->mfile,m->mbox[msg].start,0);
  891. #endif
  892.  
  893.         size = m->mbox[msg].size;
  894.         m->current = msg;
  895.         header = NOHEADER;
  896.         mbxheader = 0;
  897.         if((*argv[0] == 'v') || (m->stype == 'H'))
  898.             verbose = 1;    /* display all header lines */
  899.         else
  900.             verbose = 0;
  901.  
  902.         tprintf("Message #%d %s\n", msg,
  903.             m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  904.  
  905.         /* When you have sysop privs,
  906.          * only mark your own private area as read and changed.
  907.          * other areas, only mark as read, NOT changed !
  908.          * for regular users, simply mark all as read and changed.
  909.          * That way sysops can read other's mail without
  910.          * marking stuff read that really wasn't read by
  911.          * the right person !
  912.          * for regular users, simply mark as read.
  913.          * 910312 - WG7J
  914.          */
  915.         if(!(m->mbox[msg].status & BM_READ)) {
  916.             m->mbox[msg].status |= BM_READ;
  917.                 /* regular users */
  918.             if(!(m->privs & SYSOP_CMD) || \
  919.                ((m->privs & SYSOP_CMD) && !strcmp(m->name,m->area))) /*sysops*/
  920.                     m->change = 1;
  921.             m->newmsgs--;
  922.         }
  923.         --lin;
  924.         col = 0;
  925.         while (!feof(m->mfile) && size > 0) {
  926.             pathcol = 0; /* kf8nh */
  927.             for (col = 0;  col < MAXCOL;) {
  928.                 c = getc(m->mfile);
  929.                 size--;
  930.                 if (feof(m->mfile) || size == 0) /* end this line */
  931.                     break;
  932.                 if (c == '\t') {
  933.                     cnt = col + 8 - (col & 7);
  934.                     if (cnt >= MAXCOL) /* end this line */
  935.                         break;
  936.                     while (col < cnt)
  937.                         buf[col++] = ' ';
  938.                 } else {
  939.                     if (c == '\n')
  940.                         break;
  941.                     buf[col++] = c;
  942.                 }
  943.             }
  944.             if(col < MAXCOL)
  945.                 buf[col++] = '\n';
  946.             buf[col] = '\0';
  947.             if(mbxheader > 0) {
  948.                  /* Digest R: lines and display as a Path: line */
  949.                  if(strncmp(buf,"R:",2) != 0 ||
  950.                 (cp = strchr(buf,'@')) == NULLCHAR) {
  951.                   tputc('\n');
  952.                   mbxheader = -1; /* don't get here again */
  953.                   verbose = 1;
  954.                  }
  955.                  else {
  956.                   if(*(++cp) == ':')
  957.                        ++cp;
  958.                   for(cp2 = cp; isalnum(*cp2); ++cp2)  ;
  959.                   *cp2 = '\0';
  960.                   if(mbxheader++ == 1) {
  961.                        tputs(Hdrs[PATH]);
  962.                        pathcol = 5;
  963.                        --lin;
  964.                   }
  965.                   else {
  966.                        tputc('!');
  967.                        if(++pathcol + strlen(cp) > MAXCOL-3){
  968.                         tputs("\n      ");
  969.                         pathcol = 5;
  970.                         --lin;
  971.                        }
  972.                   }
  973.                   tputs(cp);
  974.                   pathcol += strlen(cp);
  975.                   ++lin;    /* to allow for not printing it later */
  976.                  }
  977.             }
  978.             if(col == 1 && !verbose && !mbxheader)
  979.                  /* last header line reached */
  980.                  mbxheader = 1;
  981.             if(verbose)
  982.                 tputs(buf);
  983.             if(!verbose && !mbxheader){
  984.                 lastheader = header;
  985.                 if(!isspace(*buf))
  986.                     header = htype(buf);
  987.                 else
  988.                     header = lastheader;
  989.                 switch(header) {
  990.                 case TO:
  991.                 case CC:
  992.                 case FROM:
  993.                 case DATE:
  994.                 case SUBJECT:
  995.                 case REPLYTO:
  996.                 case APPARTO:
  997.                 case ORGANIZATION:
  998.                     tputs(buf);
  999.                     break;
  1000.                 default:
  1001.                     ++lin;
  1002.                 }
  1003.             }
  1004.             col = 0;
  1005.             if(usemore && --lin == 0){
  1006.                 if(m->type == TELNET_LINK || m->type == TIP_LINK)
  1007.                     c = tkeywait("--More--",0,m->linemode);
  1008.                 else  /* For AX.25 and NET/ROM connects - WG7J */
  1009.                     c = mykeywait("More(N=no)? ",m);
  1010.                 lin = m->morerows;
  1011.                 if(c == -1 || c == 'q' || c == 'Q')
  1012.                     break;
  1013.                 if(c == '\n' || c == '\r')
  1014.                     lin = 1;
  1015.             }
  1016.         }
  1017.     }
  1018.       }
  1019. iamdone:
  1020.     /* If this was 'RM' or 'VM',
  1021.      * free the memory allocated for myargv[] - WG7J
  1022.      */
  1023.     if(m->stype == 'M') {
  1024.         for(i=1;i<argc;i++)
  1025.             free(myargv[i]);
  1026.     }
  1027.     return 0;
  1028. }
  1029.  
  1030. /* Set up m->to when replying to a message. The subject is returned in
  1031.  * m->line.
  1032.  */
  1033. int
  1034. mbx_reply(argc,argv,m,cclist,rhdr)
  1035. int argc;
  1036. char *argv[];
  1037. struct mbx *m;
  1038. struct list **cclist;    /* Pointer to buffer for pointers to cc recipients */
  1039. char **rhdr;        /* Pointer to buffer for extra reply headers */
  1040. {
  1041.     char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  1042.     char *cp;
  1043.     int msg, lastheader, header = NOHEADER;
  1044.     long size;
  1045.  
  1046.     /* Free anything that might be allocated
  1047.      * since the last call to mbx_to() or mbx_reply()
  1048.      */
  1049.     free(m->to);
  1050.     m->to = NULLCHAR;
  1051.     free(m->tofrom);
  1052.     m->tofrom = NULLCHAR;
  1053.     free(m->tomsgid);
  1054.     m->tomsgid = NULLCHAR;
  1055.     free(m->origto);
  1056.     m->origto = NULLCHAR;
  1057.     subject[0] = '\0';
  1058.  
  1059.     if(argc == 1)
  1060.          msg = m->current;
  1061.     else
  1062.          msg = atoi(argv[1]);
  1063.     if (m->mfile == NULLFILE) {
  1064.          if(m->sid & MBX_SID)
  1065.           tputs("NO - ");
  1066.         tputs(Nomail);
  1067.         return 0;
  1068.     }
  1069.     if(msg < 1 || msg > m->nmsgs) {
  1070.          if(m->sid & MBX_SID)
  1071.           tputs("NO - ");
  1072.          tputs(Badmsg);
  1073.          return -1;
  1074.     }
  1075.     fseek(m->mfile,m->mbox[msg].start,0);
  1076.     size = m->mbox[msg].size;
  1077.     m->current = msg;
  1078.     while(size > 0 && fgets(m->line,MBXLINE-1,m->mfile) != NULLCHAR) {
  1079.          size -= strlen(m->line);
  1080.          if(m->line[0] == '\n')    /* end of header */
  1081.           break;
  1082.          rip(m->line);
  1083.          lastheader = header;
  1084.          if(!isspace(m->line[0])) {
  1085.           header = htype(m->line);
  1086.           lastheader = NOHEADER;
  1087.          }
  1088.          switch(header) {
  1089.          case SUBJECT:
  1090.           if(strlen(m->line) > 11 && !strnicmp(&m->line[9],"Re:",3))
  1091.                strcpy(subject,&m->line[9]);
  1092.           else
  1093.                sprintf(subject,"Re: %s",&m->line[9]);
  1094.           break;
  1095.          case FROM:
  1096.           if(m->to == NULLCHAR && (cp = getaddress(m->line,0)) !=
  1097.              NULLCHAR)
  1098.                m->to = strdup(cp);
  1099.           break;
  1100.          case REPLYTO:
  1101.           if((cp = getaddress(m->line,0)) != NULLCHAR) {
  1102.                free(m->to);
  1103.                m->to = strdup(cp);
  1104.           }
  1105.           break;
  1106.          case MSGID:
  1107.           free(msgid);
  1108.           msgid = strdup(&m->line[12]);
  1109.           break;
  1110.          case DATE:
  1111.           free(date);
  1112.           date = strdup(&m->line[6]);
  1113.           break;
  1114. #ifdef notdef
  1115.          /* don't want a reply back to myself - WG7J */
  1116.          case TO:
  1117.          case APPARTO:
  1118. #endif
  1119.          case CC:
  1120.           /* Get addresses on To, Cc and Apparently-To lines */
  1121.           cp = m->line;
  1122.           m->line[strlen(cp)+1] = '\0';    /* add extra null at end */
  1123.           for(;;) {
  1124.                if((cp = getaddress(cp,lastheader == header ||
  1125.                        cp != m->line)) == NULLCHAR)
  1126.                 break;
  1127.                addlist(cclist,cp,0);
  1128.                /* skip to next address, if any */
  1129.                cp += strlen(cp) + 1;
  1130.           }
  1131.           break;
  1132.          }
  1133.     }
  1134.     if(msgid != NULLCHAR || date != NULLCHAR) {
  1135.          *rhdr = mallocw(LINELEN);
  1136.          sprintf(*rhdr,"In-Reply-To: your message ");
  1137.          if(date != NULLCHAR) {
  1138.           sprintf(m->line,"of %s.\n",date);
  1139.           strcat(*rhdr,m->line);
  1140.           if(msgid != NULLCHAR)
  1141.                strcat(*rhdr,"             ");
  1142.          }
  1143.          if(msgid != NULLCHAR) {
  1144.           sprintf(m->line,"%s\n",msgid);
  1145.           strcat(*rhdr,m->line);
  1146.          }
  1147.          free(msgid);
  1148.          free(date);
  1149.     }
  1150.     strcpy(m->line,subject);
  1151.     return 0;
  1152. }
  1153.  
  1154. #ifdef USERLOG
  1155.  
  1156. /*get the last message listed/read
  1157.  *from the areaname.USR file
  1158.  *keeps track for each user.
  1159.  *February '92, WG7J
  1160.  */
  1161. void
  1162. getlastread(m)
  1163. struct mbx *m;
  1164. {
  1165.     FILE *Alog;
  1166.     char buf[256];
  1167.     char *cp;
  1168.     int found=0;
  1169.  
  1170.     m->lastread = m->newlastread = 0L;
  1171.  
  1172.     sprintf(buf,"%s/%s.usr",Mailspool,m->area);
  1173.     if ((Alog = fopen(buf,"r+")) == NULLFILE) {
  1174.         /* USR file doesn't exist, create it */
  1175.         if((Alog = fopen(buf,"w")) == NULLFILE)
  1176.             return;
  1177.         /* Add this user as first one */
  1178.         sprintf(buf,"%s 0\n",m->name);
  1179.         fputs(buf,Alog);
  1180.         fclose(Alog);
  1181.         return;
  1182.     }
  1183.     /*Find user in the usr file for this area*/
  1184.     for(;;) {
  1185.         if(fgets(buf,sizeof(buf),Alog) == NULLCHAR)
  1186.             break;
  1187.         if((cp=strchr(buf,' ')) != NULLCHAR)
  1188.             *cp = '\0';
  1189.         if(!stricmp(m->name,buf)) {
  1190.             /*found user*/
  1191.             cp++;
  1192.             while(*cp == ' ')   /*skip blanks*/
  1193.                 cp++;
  1194.             m->lastread = atol(cp);
  1195.             found = 1;
  1196.             break;
  1197.         }
  1198.     }
  1199.     if(!found) {
  1200.         /*Add user*/
  1201.         sprintf(buf,"%s 0\n",m->name);
  1202.         fputs(buf,Alog);
  1203.     }
  1204.     fclose(Alog);
  1205.     return;
  1206. }
  1207.  
  1208. /* Write the new last read id number to the USR file - WG7J
  1209.  * only update if this is not a bbs,
  1210.  * current area is a public area and not 'help',
  1211.  * or anything that starts with 'sys',
  1212.  * and a new message was actually listed/read
  1213.  */
  1214. void
  1215. setlastread(m)
  1216. struct mbx *m;
  1217. {
  1218.     FILE *Alog, *tfile;
  1219.     char buf[256];
  1220.     char tmpname[80];
  1221.     char *cp;
  1222.  
  1223.     if((m->sid & MBX_SID) || (m->newlastread <= m->lastread) )
  1224.         return;
  1225.  
  1226.     if( (isarea(m->area) && strcmp(m->area,"help")) ||
  1227.         !strncmp(m->area,"sys",3) ) {
  1228.  
  1229. #ifdef notdef
  1230.     tprintf("SETLAST: %d\n",m->newlastread);
  1231. #endif
  1232.  
  1233.  
  1234.         sprintf(buf,"%s/%s.usr",Mailspool,m->area);
  1235.  
  1236.         /* Rename the USR file to a tempfile */
  1237. #ifdef UNIX
  1238.     strcpy(tmpname, buf);
  1239.     strcat(tmpname, ".bak");
  1240. #else
  1241.         tmpnam(tmpname);
  1242. #endif
  1243.         if(rename(buf,tmpname))
  1244.             /* Can't rename ??? */
  1245.             return;
  1246.  
  1247.         if((Alog = fopen(buf,"w")) == NULLFILE) {
  1248.             /* can't creat new USR file ???*/
  1249.             rename(tmpname,buf);    /* try to undo the damage */
  1250.             return;
  1251.         }
  1252.  
  1253.         if((tfile = fopen(tmpname,"r")) == NULLFILE)
  1254.             /* can't open renamed file ??? */
  1255.             return;
  1256.  
  1257.         /*Write all users back, but update this one!*/
  1258.         while(fgets(buf,sizeof(buf),tfile) != NULLCHAR) {
  1259.             if((cp=strchr(buf,' ')) != NULLCHAR)
  1260.                 *cp = '\0';
  1261.             if(!stricmp(m->name,buf)) {
  1262.                 /*found this user*/
  1263.                 sprintf(buf,"%s %lu\n",m->name,m->newlastread);
  1264.             } else
  1265.                 *cp = ' '; /* restore the space !*/
  1266.             fputs(buf,Alog);
  1267.         }
  1268.         fclose(tfile);
  1269.         unlink(tmpname);
  1270.         fclose(Alog);
  1271.     }
  1272.     return;
  1273. }
  1274.  
  1275. #endif /*USERLOG*/
  1276.  
  1277. void
  1278. scanmail(m)         /* Get any new mail */
  1279. struct mbx *m;
  1280. {
  1281.     FILE *nfile;
  1282.     int ret;
  1283.     char buf[256];
  1284.     long diff;
  1285.  
  1286.     if ((diff = isnewmail(m)) == 0L)
  1287.         return;
  1288.     if(lockit(m))
  1289.         return;
  1290.     if(m->mfile == NULLFILE || diff < 0L) {
  1291.         /* This is the first time scanmail is called, or the
  1292.          * mail file size has decreased. In the latter case,
  1293.          * any changes we did to this area will be lost, but this
  1294.          * is not fatal.
  1295.          */
  1296.         initnotes(m);
  1297.         rmlock(Mailspool,m->area);
  1298.         return;
  1299.     }
  1300.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  1301.     if ((nfile = fopen(buf,READ_TEXT)) == NULLFILE)
  1302.         tprintf(Noaccess,buf);
  1303.     else {
  1304.         /* rewind tempfile */
  1305.         fseek(m->mfile,0L,0);
  1306. /*
  1307.         oldcnt = m->nmsgs;
  1308.         oldnew = m->newmsgs;
  1309. */
  1310.         /* Reread all messages since size they may have changed
  1311.          * in size after a X-Forwarded-To line was added.
  1312.          */
  1313.         m->nmsgs = 0;
  1314. #ifdef USERLOG
  1315.         m->newmsgs = 0;
  1316.         /* m->current = 0;*/
  1317. #endif
  1318.         ret = readnotes(m,nfile,1);   /* get the mail */
  1319.         m->mboxsize = ftell(nfile);
  1320.         if(!stricmp(m->name,m->area))
  1321.             m->mysize = m->mboxsize;
  1322.         (void) fclose(nfile);
  1323.         if (ret != 0)
  1324.             tprintf("Error updating mail file\n");
  1325.     }
  1326.     rmlock(Mailspool,m->area);
  1327. }
  1328.  
  1329. /* Check the current mailbox to see if new mail has arrived.
  1330.  * Returns the difference in size.
  1331.  */
  1332. static long
  1333. isnewmail(m)
  1334. struct mbx *m;
  1335. {
  1336.     char buf[256];
  1337.     sprintf(buf,"%s/%s.txt",Mailspool,m->area);
  1338.     return fsize(buf) - m->mboxsize;
  1339. }
  1340.  
  1341. /* Check if the private mail area has changed */
  1342. long
  1343. isnewprivmail(m)
  1344. struct mbx *m;
  1345. {
  1346.     long cnt;
  1347.     char buf[256];
  1348.     sprintf(buf,"%s/%s.txt",Mailspool,m->name);
  1349.     cnt = m->mysize;
  1350.     m->mysize = fsize(buf);
  1351.     return m->mysize - cnt; /* != 0 not more than once */
  1352. }
  1353. #endif
  1354.  
  1355. /* This function returns the length of a file. The proper thing would be
  1356.  * to use stat(), but it fails when using DesqView together with Turbo-C
  1357.  * code.
  1358.  */
  1359. long
  1360. fsize(name)
  1361. char *name;
  1362. {
  1363.     long cnt;
  1364.     FILE *fp;
  1365.     if((fp = fopen(name,READ_TEXT)) == NULLFILE)
  1366.         return -1L;
  1367.     fseek(fp,0L,2);
  1368.     cnt = ftell(fp);
  1369.     fclose(fp);
  1370.     return cnt;
  1371. }
  1372.  
  1373. /* close the temporary mail file */
  1374. static void
  1375. mfclose(m)
  1376. struct mbx *m;
  1377. {
  1378.     if(m->mfile != NULLFILE)
  1379.         fclose(m->mfile);
  1380.     m->mfile = NULLFILE;
  1381.     m->nmsgs = 0;           /* MDMII: forwarding loop saver */
  1382. #ifdef SETVBUF
  1383.     free(m->stdoutbuf);
  1384.     m->stdoutbuf = NULLCHAR;
  1385. #endif
  1386. }
  1387.  
  1388. /* Print prompt and read one character, telnet version */
  1389. int
  1390. tkeywait(prompt,flush,linemode)
  1391. char *prompt;    /* Optional prompt */
  1392. int flush;    /* Flush queued input? */
  1393. int linemode;    /* Negotiate line mode? */
  1394. {
  1395.     int c, cl, i, oldimode,oldomode;
  1396.  
  1397.     if(flush && socklen(Curproc->input,0) != 0)
  1398.         recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  1399.     if(prompt == NULLCHAR)
  1400.         prompt = "Hit enter to continue"; 
  1401.     tprintf("%s",prompt);
  1402.     /* hack - handle Unix telnet clients correctly */
  1403.     if (linemode)
  1404.         tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,2,IAC,SE);
  1405.     tprintf("%c%c%c",IAC,WILL,TN_ECHO);
  1406.     usflush(Curproc->output);
  1407.  
  1408.     /* discard the response */
  1409.  
  1410.     oldimode = sockmode(Curproc->input,SOCK_BINARY);
  1411.     oldomode = sockmode(Curproc->output,SOCK_BINARY);
  1412.  
  1413.     while((c = rrecvchar(Curproc->input)) == IAC){
  1414.         c = rrecvchar(Curproc->input);
  1415.         if(c == SB) {
  1416.             if((c = rrecvchar(Curproc->input)) == EOF)
  1417.                 break;
  1418.             cl = c;
  1419.             c = rrecvchar(Curproc->input);
  1420.             while((c != EOF) && !(cl == IAC && c == SE)) {
  1421.                 cl = c;
  1422.                 c = rrecvchar(Curproc->input);
  1423.             }
  1424.         } else if(c > 250 && c < 255)
  1425.             rrecvchar(Curproc->input);
  1426.     }
  1427.  
  1428.     sockmode(Curproc->output,oldomode);
  1429.     sockmode(Curproc->input,oldimode);
  1430.  
  1431.     /* Get rid of the prompt */
  1432.     for(i=strlen(prompt);i != 0;i--)
  1433.         tputc('\b');
  1434.     for(i=strlen(prompt);i != 0;i--)
  1435.         tputc(' ');
  1436.     for(i=strlen(prompt);i != 0;i--)
  1437.         tputc('\b');
  1438.     tprintf("%c%c%c",IAC,WONT,TN_ECHO);
  1439.     if (linemode)
  1440.         tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,1,IAC,SE);
  1441.     usflush(Curproc->output);
  1442.     return c;
  1443. }
  1444.  
  1445. /* Print prompt and read reply,
  1446.  * AX.25 and NETROM version - WG7J
  1447.  * 'N' or 'n' returns -1, everything else return 0.
  1448.  */
  1449. int
  1450. mykeywait(prompt,m)
  1451. char *prompt;
  1452. struct mbx *m;
  1453. {
  1454.     int c;
  1455.     
  1456.     tputs(prompt);
  1457.     usflush(Curproc->output);
  1458.  
  1459.     if(recvline(m->user, m->line, MBXLINE) == -1) {
  1460.         return -1;
  1461.     }
  1462.  
  1463.     /* Only 'N' or 'n' really matters */
  1464.     if(strchr(m->line,'N')!=0 || strchr(m->line,'n')!=0)
  1465.         return -1;
  1466.     return 0;
  1467. }
  1468.